home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / PNGLIB06.ZIP / PNGWRITE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  12.9 KB  |  400 lines

  1.  
  2. /* pngwrite.c - general routines to write a png file
  3.  
  4.    pnglib version 0.6
  5.    For conditions of distribution and use, see copyright notice in png.h
  6.    Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
  7.    May 1, 1995
  8.    */
  9.  
  10. /* get internal access to png.h */
  11. #define PNG_INTERNAL
  12. #include "png.h"
  13.  
  14. /* Writes all the png information.  This is the suggested way to use
  15.    the library.  If you have a new chunk to add, make a function to
  16.    write it, and put it in the correct location here.  If you want
  17.    the chunk written after the image data, put it in png_write_end().
  18.    I strongly encurage you to supply a PNG_INFO_ flag, and check
  19.    info->valid before writing the chunk, as that will keep the code
  20.    from breaking if you want to just write a plain png file.
  21.    If you have long comments, I suggest writing them in png_write_end(),
  22.    and compressing them. */
  23. void
  24. png_write_info(png_struct *png_ptr, png_info *info)
  25. {
  26.    png_write_sig(png_ptr); /* write PNG signature */
  27.    /* write IHDR information. */
  28.    png_write_IHDR(png_ptr, info->width, info->height, info->bit_depth,
  29.       info->color_type, info->compression_type, info->filter_type,
  30.       info->interlace_type);
  31.    /* the rest of these check to see if the valid field has the appropriate
  32.       flag set, and if it does, writes the chunk. */
  33.    if (info->valid & PNG_INFO_gAMA)
  34.       png_write_gAMA(png_ptr, info->gamma);
  35.    if (info->valid & PNG_INFO_sBIT)
  36.       png_write_sBIT(png_ptr, &(info->sig_bit), info->color_type);
  37.    if (info->valid & PNG_INFO_cHRM)
  38.       png_write_cHRM(png_ptr,
  39.          info->x_white, info->y_white,
  40.          info->x_red, info->y_red,
  41.          info->x_green, info->y_green,
  42.          info->x_blue, info->y_blue);
  43.    if (info->valid & PNG_INFO_PLTE)
  44.       png_write_PLTE(png_ptr, info->palette, info->num_palette);
  45.    if (info->valid & PNG_INFO_tRNS)
  46.       png_write_tRNS(png_ptr, info->trans, &(info->trans_values),
  47.          info->num_trans, info->color_type);
  48.    if (info->valid & PNG_INFO_bKGD)
  49.       png_write_bKGD(png_ptr, &(info->background), info->color_type);
  50.    if (info->valid & PNG_INFO_hIST)
  51.       png_write_hIST(png_ptr, info->hist, info->num_palette);
  52.    if (info->valid & PNG_INFO_pHYs)
  53.       png_write_pHYs(png_ptr, info->x_pixels_per_unit,
  54.          info->y_pixels_per_unit, info->phys_unit_type);
  55.    if (info->valid & PNG_INFO_oFFs)
  56.       png_write_oFFs(png_ptr, info->x_offset, info->y_offset,
  57.          info->offset_unit_type);
  58.    if (info->valid & PNG_INFO_tIME)
  59.       png_write_tIME(png_ptr, &(info->mod_time));
  60.    /* Check to see if we need to write text chunks */
  61.    if (info->num_text)
  62.    {
  63.       int i; /* local counter */
  64.  
  65.       /* loop through the text chunks */
  66.       for (i = 0; i < info->num_text; i++)
  67.       {
  68.          /* if chunk is compressed */
  69.          if (info->text[i].compression >= 0)
  70.          {
  71.             /* write compressed chunk */
  72.             png_write_zTXt(png_ptr, info->text[i].key,
  73.                info->text[i].text, info->text[i].text_length,
  74.                info->text[i].compression);
  75.          }
  76.          else
  77.          {
  78.             /* write uncompressed chunk */
  79.             png_write_tEXt(png_ptr, info->text[i].key,
  80.                info->text[i].text, info->text[i].text_length);
  81.          }
  82.       }
  83.    }
  84. }
  85.  
  86. /* writes the end of the png file.  If you don't want to write comments or
  87.    time information, you can pass NULL for info.  If you already wrote these
  88.    in png_write_info(), do not write them again here.  If you have long
  89.    comments, I suggest writing them here, and compressing them. */
  90. void
  91. png_write_end(png_struct *png_ptr, png_info *info)
  92. {
  93.    /* see if user wants us to write information chunks */
  94.    if (info)
  95.    {
  96.       /* check to see if user has supplied a time chunk */
  97.       if (info->valid & PNG_INFO_tIME)
  98.          png_write_tIME(png_ptr, &(info->mod_time));
  99.       /* check to see if we need to write comment chunks */
  100.       if (info->num_text)
  101.       {
  102.          int i; /* local index variable */
  103.  
  104.          /* loop through comment chunks */
  105.          for (i = 0; i < info->num_text; i++)
  106.          {
  107.             /* check to see if comment is to be compressed */
  108.             if (info->text[i].compression >= 0)
  109.             {
  110.                /* write compressed chunk */
  111.                png_write_zTXt(png_ptr, info->text[i].key,
  112.                   info->text[i].text, info->text[i].text_length,
  113.                   info->text[i].compression);
  114.             }
  115.             else
  116.             {
  117.                /* write uncompressed chunk */
  118.                png_write_tEXt(png_ptr, info->text[i].key,
  119.                   info->text[i].text, info->text[i].text_length);
  120.             }
  121.          }
  122.       }
  123.    }
  124.    /* write end of png file */
  125.    png_write_IEND(png_ptr);
  126. }
  127.  
  128. /* initialize the info structure */
  129. void
  130. png_info_init(png_info *info)
  131. {
  132.    /* set everything to 0 */
  133.    memset(info, 0, sizeof (png_info));
  134. }
  135.  
  136. void
  137. png_convert_from_struct_tm(png_time *ptime, struct tm *ttime)
  138. {
  139.    ptime->year = 1900 + ttime->tm_year;
  140.    ptime->month = ttime->tm_mon + 1;
  141.    ptime->day = ttime->tm_mday;
  142.    ptime->hour = ttime->tm_hour;
  143.    ptime->minute = ttime->tm_min;
  144.    ptime->second = ttime->tm_sec;
  145. }
  146.  
  147. void
  148. png_convert_from_time_t(png_time *ptime, time_t ttime)
  149. {
  150.    struct tm *tbuf;
  151.  
  152.    tbuf = gmtime(&ttime);
  153.    png_convert_from_struct_tm(ptime, tbuf);
  154. }
  155.  
  156. /* initialize png structure, and allocate any memory needed */
  157. void
  158. png_write_init(png_struct *png_ptr)
  159. {
  160.    jmp_buf tmp_jmp; /* to save current jump buffer */
  161.  
  162.    /* save jump buffer */
  163.    memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  164.    /* reset all variables to 0 */
  165.    memset(png_ptr, 0, sizeof (png_struct));
  166.    /* restore jump buffer */
  167.    memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  168.  
  169.    /* initialize zbuf - compression buffer */
  170.    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
  171.    png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
  172.    /* initialize zlib */
  173.    png_ptr->zstream = &(png_ptr->zstream_struct);
  174.    png_ptr->zstream->zalloc = png_zalloc;
  175.    png_ptr->zstream->zfree = png_zfree;
  176.    png_ptr->zstream->opaque = png_ptr;
  177.    deflateInit(png_ptr->zstream, Z_BEST_COMPRESSION);
  178.    png_ptr->zstream->next_out = png_ptr->zbuf;
  179.    png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
  180. }
  181.  
  182. /* write a few rows of image data.  If the image is interlaced,
  183.    either you will have to write the 7 sub images, or, if you
  184.    have called png_set_interlace_handling(), you will have to
  185.    "write" the image seven times */
  186. void
  187. png_write_rows(png_struct *png_ptr, png_byte **row,
  188.    png_uint_32 num_rows)
  189. {
  190.    png_uint_32 i; /* row counter */
  191.    png_byte **rp; /* row pointer */
  192.  
  193.    /* loop through the rows */
  194.    for (i = 0, rp = row; i < num_rows; i++, rp++)
  195.    {
  196.       png_write_row(png_ptr, *rp);
  197.    }
  198. }
  199.  
  200. /* write the image.  You only need to call this function once, even
  201.    if you are writing an interlaced image. */
  202. void
  203. png_write_image(png_struct *png_ptr, png_byte **image)
  204. {
  205.    png_uint_32 i; /* row index */
  206.    int pass, num_pass; /* pass variables */
  207.    png_byte **rp; /* points to current row */
  208.  
  209.    /* intialize interlace handling.  If image is not interlaced,
  210.       this will set pass to 1 */
  211.    num_pass = png_set_interlace_handling(png_ptr);
  212.    /* loop through passes */
  213.    for (pass = 0; pass < num_pass; pass++)
  214.    {
  215.       /* loop through image */
  216.       for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
  217.       {
  218.          png_write_row(png_ptr, *rp);
  219.          rp++;
  220.       }
  221.    }
  222. }
  223.  
  224. /* write a row of image data */
  225. void
  226. png_write_row(png_struct *png_ptr, png_byte *row)
  227. {
  228.    /* initialize transformations and other stuff if first time */
  229.    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
  230.    {
  231.       png_write_start_row(png_ptr);
  232.    }
  233.  
  234.    /* if interlaced and not interested in row, return */
  235.    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
  236.    {
  237.       switch (png_ptr->pass)
  238.       {
  239.          case 0:
  240.             if (png_ptr->row_number & 7)
  241.             {
  242.                png_write_finish_row(png_ptr);
  243.                return;
  244.             }
  245.             break;
  246.          case 1:
  247.             if ((png_ptr->row_number & 7) || png_ptr->width < 5)
  248.             {
  249.                png_write_finish_row(png_ptr);
  250.                return;
  251.             }
  252.             break;
  253.          case 2:
  254.             if ((png_ptr->row_number & 7) != 4)
  255.             {
  256.                png_write_finish_row(png_ptr);
  257.                return;
  258.             }
  259.             break;
  260.          case 3:
  261.             if ((png_ptr->row_number & 3) || png_ptr->width < 3)
  262.             {
  263.                png_write_finish_row(png_ptr);
  264.                return;
  265.             }
  266.             break;
  267.          case 4:
  268.             if ((png_ptr->row_number & 3) != 2)
  269.             {
  270.                png_write_finish_row(png_ptr);
  271.                return;
  272.             }
  273.             break;
  274.          case 5:
  275.             if ((png_ptr->row_number & 1) || png_ptr->width < 2)
  276.             {
  277.                png_write_finish_row(png_ptr);
  278.                return;
  279.             }
  280.             break;
  281.          case 6:
  282.             if (!(png_ptr->row_number & 1))
  283.             {
  284.                png_write_finish_row(png_ptr);
  285.                return;
  286.             }
  287.             break;
  288.       }
  289.    }
  290.  
  291.    /* set up row info for transformations */
  292.    png_ptr->row_info.color_type = png_ptr->color_type;
  293.    png_ptr->row_info.width = png_ptr->usr_width;
  294.    png_ptr->row_info.channels = png_ptr->usr_channels;
  295.    png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
  296.    png_ptr->row_info.pixel_depth = png_ptr->row_info.bit_depth *
  297.       png_ptr->row_info.channels;
  298.    png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
  299.       (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
  300.  
  301.    /* copy users row into buffer, leaving room for filter byte */
  302.    memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
  303.  
  304.    /* handle interlacing */
  305.    if (png_ptr->interlaced && png_ptr->pass < 6 &&
  306.       (png_ptr->transformations & PNG_INTERLACE))
  307.    {
  308.       png_do_write_interlace(&(png_ptr->row_info),
  309.          png_ptr->row_buf + 1, png_ptr->pass);
  310.       /* this should always get caught above, but still ... */
  311.       if (!(png_ptr->row_info.width))
  312.       {
  313.          png_write_finish_row(png_ptr);
  314.          return;
  315.       }
  316.    }
  317.  
  318.    /* handle other transformations */
  319.    if (png_ptr->transformations)
  320.       png_do_write_transformations(png_ptr);
  321.  
  322.    /* filter rows that have been proved to help */
  323.    if (png_ptr->bit_depth >= 8 && png_ptr->color_type != 3)
  324.    {
  325.       /* save row to previous row */
  326.       memcpy(png_ptr->save_row, png_ptr->row_buf,
  327.          (png_size_t)png_ptr->row_info.rowbytes + 1);
  328.  
  329.       /* filter row */
  330.       png_write_filter_row(&(png_ptr->row_info), png_ptr->row_buf,
  331.          png_ptr->prev_row);
  332.  
  333.       /* trade saved pointer and prev pointer so next row references are correctly */
  334.       { /* scope limiter */
  335.          png_byte *tptr;
  336.  
  337.          tptr = png_ptr->prev_row;
  338.          png_ptr->prev_row = png_ptr->save_row;
  339.          png_ptr->save_row = tptr;
  340.       }
  341.    }
  342.    else
  343.       /* set filter row to "none" */
  344.       png_ptr->row_buf[0] = 0;
  345.  
  346.    /* set up the zlib input buffer */
  347.    png_ptr->zstream->next_in = png_ptr->row_buf;
  348.    png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
  349.  
  350.    /* repeat until we have compressed all the data */
  351.    do
  352.    {
  353.       int ret; /* return of zlib */
  354.  
  355.       /* compress the data */
  356.       ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
  357.       /* check for compression errors */
  358.       if (ret != Z_OK)
  359.       {
  360.          if (png_ptr->zstream->msg)
  361.             png_error(png_ptr, png_ptr->zstream->msg);
  362.          else
  363.             png_error(png_ptr, "zlib error");
  364.       }
  365.  
  366.       /* see if it is time to write another IDAT */
  367.       if (!png_ptr->zstream->avail_out)
  368.       {
  369.          /* write the IDAT and reset the zlib output buffer */
  370.          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
  371.          png_ptr->zstream->next_out = png_ptr->zbuf;
  372.          png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
  373.       }
  374.    /* repeat until all data has been compressed */
  375.    } while (png_ptr->zstream->avail_in);
  376.  
  377.    /* finish row - updates counters and flushes zlib if last row */
  378.    png_write_finish_row(png_ptr);
  379. }
  380.  
  381. /* free any memory used in png struct */
  382. void
  383. png_write_destroy(png_struct *png_ptr)
  384. {
  385.    jmp_buf tmp_jmp; /* save jump buffer */
  386.  
  387.    /* free any memory zlib uses */
  388.    deflateEnd(png_ptr->zstream);
  389.    /* free our memory.  png_free checks NULL for us. */
  390.    png_large_free(png_ptr, png_ptr->zbuf);
  391.    png_large_free(png_ptr, png_ptr->row_buf);
  392.    png_large_free(png_ptr, png_ptr->prev_row);
  393.    png_large_free(png_ptr, png_ptr->save_row);
  394.    /* reset structure */
  395.    memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  396.    memset(png_ptr, 0, sizeof (png_struct));
  397.    memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  398. }
  399.  
  400.